<?php


namespace app\service;

use EasyWeChat\MiniApp\Application;

class MiniProgramService
{
    protected $app;

    /**
     * 构造函数
     */
    public function __construct()
    {
        $this->app = new Application([
            'app_id' => env('WECHAT_MINi_APP_ID'),
            'secret' => env('WECHAT_MINI_SECRET'),
            // 以下配置为可选项
            'token' => env('WECHAT_MINI_TOKEN', ''),
            'aes_key' => env('WECHAT_MINI_AES_KEY', ''),
        ]);
    }

    public function getConfig()
    {
        return [
            'app_id' => env('WECHAT_MINi_APP_ID'),
            'secret' => env('WECHAT_MINI_SECRET'),
            // 以下配置为可选项
            'token' => env('WECHAT_MINI_TOKEN', ''),
            'aes_key' => env('WECHAT_MINI_AES_KEY', ''),
        ];
    }

    /**
     * 获取小程序应用实例
     * @return Application
     */
    public function getApp(): Application
    {
        return $this->app;
    }

    /**
     * 获取小程序工具类
     * @return object
     */
    public function getUtils()
    {
        return $this->app->getUtils();
    }

    /**
     * 获取小程序openid
     * @param string $code 登录时获取的code
     * @return string openid
     */
    public function getOpenid(string $code): string
    {
        $utils = $this->getUtils();
        $response = $utils->codeToSession($code);
        return $response['openid'] ?? '';
    }

    /**
     * 获取会话信息
     * @param string $code 登录时获取的code
     * @return array 包含session_key、openid等信息的数组
     */
    public function getSessionInfo(string $code): array
    {
        $utils = $this->getUtils();
        return $utils->codeToSession($code);
    }

    // 生成小程序码
    public function getMiniQrcode(array $params,$filePath='upload/goods',$filedName=''): string
    {
        try {
            $response = $this->app->getClient()->postJson('/wxa/getwxacodeunlimit', $params);
            $path = root_path() . 'public/'.$filePath;
            if (!is_dir($path)) {
                // 不存在则创建目录
                mkdir($path, 0777, true);
            }
            $fieldName = empty($filedName)?mt_rand(1111, 9999) . time() . '.png':$filedName;
            $response->saveAs( $path . '/' .$fieldName);
            // return 'upload/goods/' . $fieldName;
            return $filePath . '/' . $fieldName;
        } catch (\Throwable $e) {
            // 失败
            trace('error',$e->getTraceAsString());
            // throw new \Exception($e->getMessage());
        }
        return '';
    }

    /**
     * 解密小程序加密数据
     * @param string $sessionKey 会话密钥
     * @param string $encryptedData 包括敏感数据在内的完整用户信息的加密数据
     * @param string $iv 加密算法的初始向量
     * @return array 解密后的数据
     */
    public function decryptData(string $sessionKey, string $encryptedData, string $iv): array
    {
        $utils = $this->getUtils();
        try {
            $decryptedData = $utils->decryptSession($sessionKey, $iv, $encryptedData);
            return $decryptedData;
        } catch (\Exception $e) {
            return ['error' => $e->getMessage()];
        }
    }

    /**
     * 处理小程序登录数据
     * @param array $data 包含加密数据的数组
     * @return array 处理结果
     */
    public function handleLoginData(array $data): array
    {
        // 获取会话密钥
        $code = $data['code'] ?? '';
        if (empty($code)) {
            return ['error' => '缺少code参数'];
        }

        $sessionInfo = $this->getSessionInfo($code);
        if (!isset($sessionInfo['session_key'])) {
            return ['error' => '获取session_key失败', 'data' => $sessionInfo];
        }

        $sessionKey = $sessionInfo['session_key'];
        $openid = $sessionInfo['openid'] ?? '';
        $unionid = $sessionInfo['unionid'] ?? '';

        $result = [
            'openid' => $openid,
            'unionid' => $unionid
        ];

        // 解密用户信息
        if (isset($data['userEncryptedData']) && isset($data['userIv'])) {
            $userInfo = $this->decryptData($sessionKey, $data['userEncryptedData'], $data['userIv']);
            if (!isset($userInfo['error'])) {
                $result['userInfo'] = $userInfo;
            } else {
                $result['userInfoError'] = $userInfo['error'];
            }
        }

        // 解密手机号
        if (isset($data['phoneEncryptedData']) && isset($data['phoneIv'])) {
            $phoneInfo = $this->decryptData($sessionKey, $data['phoneEncryptedData'], $data['phoneIv']);
            if (!isset($phoneInfo['error'])) {
                $result['phoneInfo'] = $phoneInfo;
            } else {
                $result['phoneInfoError'] = $phoneInfo['error'];
            }
        }

        return $result;
    }
}
